package co.fitstart.admin.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.demo2do.core.BusinessException;
import com.demo2do.core.persistence.GenericDaoSupport;
import com.demo2do.core.persistence.annotation.Dynamic;
import com.demo2do.core.support.Page;
import com.demo2do.core.utils.DateFormatUtils;
import com.demo2do.core.utils.DateUtils;

import co.fitstart.admin.Constants;
import co.fitstart.admin.dao.TelephoneResourceDao;
import co.fitstart.admin.dao.UserDao;
import co.fitstart.admin.entity.search.TelephoneRecordSearch;
import co.fitstart.admin.entity.search.TelephoneResourceSearch;
import co.fitstart.admin.handler.UserHandler;
import co.fitstart.admin.service.TelephoneResourceService;
import co.fitstart.entity.course.CourseType;
import co.fitstart.entity.course.schedule.CourseSchedule;
import co.fitstart.entity.course.schedule.ScheduleStatus;
import co.fitstart.entity.reference.Gender;
import co.fitstart.entity.user.Student;
import co.fitstart.entity.user.TelephoneRecord;
import co.fitstart.entity.user.TelephoneResource;
import co.fitstart.entity.user.User;

/**
 * 
 * @author haiyan_xiao
 *
 */
@Service("telephoneResourceService")
public class TelephoneResourceServiceImpl implements TelephoneResourceService {
    @Dynamic
    private TelephoneResourceDao telephoneResourceDao;
    
    @Dynamic
    private UserDao userDao;
    
    @Autowired
    private UserHandler userHandler;
    
    @Autowired
    private GenericDaoSupport genericDaoSupport;
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.TelephoneResourceService#list(java.lang.String, java.util.Date, java.lang.Boolean, com.demo2do.core.support.Page)
     */
    public List<TelephoneResource> list(String period, Date day, Boolean experienced, Page page) {
        Map<String, Date> times = this.getTimes(day, period);
        
        List<TelephoneResource> telephoneResources = new ArrayList<>();
        
        if(!times.isEmpty()) {
            if(experienced == null) {
                telephoneResources = telephoneResourceDao.list(times.get("begin"), times.get("end"), page.getBeginIndex(), page.getMaxResultRecords());
            } else {
                telephoneResources = telephoneResourceDao.list(times.get("begin"), times.get("end"), experienced, page.getBeginIndex(), page.getMaxResultRecords());
            }
        }
        
        page.calculate(telephoneResources.size());
        return telephoneResources.size() > page.getEveryPage() ? telephoneResources.subList(0, page.getEveryPage()) : telephoneResources;
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.TelephoneResourceService#count(java.lang.String, java.util.Date, java.lang.Boolean)
     */
    public int count(String period, Date day, Boolean experienced) {
        Map<String, Date> times = this.getTimes(day, period);
        
        if(!times.isEmpty()) {
            if(experienced == null) {
                return telephoneResourceDao.count(times.get("begin"), times.get("end"));
            } else {
                return telephoneResourceDao.count(times.get("begin"), times.get("end"), experienced);
            }
        } else {
            return 0;
        }
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.TelephoneResourceService#list(java.util.Date, java.util.Date, java.lang.Boolean)
     */
    public List<TelephoneResource> list(Date begin, Date end, Boolean experienced) {
        List<TelephoneResource> telephoneResources = new ArrayList<>();
        
        if(experienced == null) {
            telephoneResources = telephoneResourceDao.list(begin, end);
        } else {
        	telephoneResources = telephoneResourceDao.list(begin, end, experienced);
        }
        return telephoneResources;
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.TelephoneResourceService#search(co.fitstart.admin.entity.search.TelephoneResourceSearch)
     */
    @SuppressWarnings("unchecked")
    public List<TelephoneResource> search(TelephoneResourceSearch search) {
        String s = search.buildSentenceTemplate();
        Map<String, Object> parameters = search.buildParameters();
        return genericDaoSupport.searchForList(s, parameters);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.TelephoneResourceService#create(java.lang.String, co.fitstart.entity.reference.Gender, java.lang.String, co.fitstart.entity.user.TelephoneResource)
     */
    public void create(String mobile, Gender gender, String name, TelephoneResource telephoneResource) {
        User user = userDao.load(mobile);
        
        if(user == null) {
            user = userHandler.create(mobile, name, true, Constants.USER_ACCOUNT_MOBILE_KEY, mobile);
            
            genericDaoSupport.update(user.editGender(gender));
            
            genericDaoSupport.save(telephoneResource.initilize(user));
        } else {
            throw new BusinessException("该用户已存在");
        }
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.TelephoneResourceService#load(java.lang.Long)
     */
    public TelephoneResource load(Long telephoneResourceId) {
        return genericDaoSupport.load(TelephoneResource.class, telephoneResourceId);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.TelephoneResourceService#update(co.fitstart.entity.user.TelephoneResource)
     */
    public void update(TelephoneResource telephoneResource) {
        genericDaoSupport.update(telephoneResource);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.TelephoneResourceService#addTelephoneRecord(co.fitstart.entity.user.TelephoneRecord)
     */
    public void addTelephoneRecord(TelephoneRecord telephoneRecord) {
        genericDaoSupport.save(telephoneRecord.initilize());
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.TelephoneResourceService#loadTelephoneRecord(java.lang.Long)
     */
    public TelephoneRecord loadTelephoneRecord(Long telephoneRecordId) {
        return genericDaoSupport.load(TelephoneRecord.class, telephoneRecordId);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.TelephoneResourceService#updateTelephoneRecord(co.fitstart.entity.user.TelephoneRecord)
     */
    public void updateTelephoneRecord(TelephoneRecord telephoneRecord) {
        genericDaoSupport.update(telephoneRecord);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.TelephoneResourceService#getTimes(java.util.Date, java.lang.String)
     */
    public Map<String, Date> getTimes(Date date, String period) {
        
        Map<String, Date> times = new HashMap<String, Date>();
        
        if(StringUtils.equalsIgnoreCase(period, "year")) {
            times.put("begin", DateUtils.parseDate(DateFormatUtils.format(date, "yyyy") + "-01-01", "yyyy-MM-dd"));
            times.put("end", DateUtils.parseDate(DateFormatUtils.format(date, "yyyy") + "-12-31", "yyyy-MM-dd"));
        } else if (StringUtils.equalsIgnoreCase(period, "week")) {
            times.put("begin", DateUtils.parseDate(DateFormatUtils.format(DateUtils.getFirstWeekDay(date), "yyyy-MM-dd"), "yyyy-MM-dd"));
            times.put("end", DateUtils.parseDate(DateFormatUtils.format(DateUtils.getLastWeekDay(date), "yyyy-MM-dd"), "yyyy-MM-dd"));
        } else if (StringUtils.equalsIgnoreCase(period, "month")) {
            times.put("begin", DateUtils.parseDate(DateFormatUtils.format(DateUtils.getFirstMonthDay(date), "yyyy-MM-dd"), "yyyy-MM-dd"));
            times.put("end", DateUtils.parseDate(DateFormatUtils.format(DateUtils.getLastMonthDay(date), "yyyy-MM-dd"), "yyyy-MM-dd"));
        }
        
        return times;
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.TelephoneResourceService#listUser(java.util.Date, java.util.Date, java.lang.Boolean)
     */
    public List<User> listUser(Date begin, Date end, Boolean experienced) {
        List<User> users = new ArrayList<>();
        
        if(experienced == null) {
            users = telephoneResourceDao.listUser(begin, end);
        } else {
            users = telephoneResourceDao.listUser(begin, end, experienced);
        }
        
        return users;
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.TelephoneResourceService#listUser(co.fitstart.admin.entity.search.TelephoneResourceSearch)
     */
    @SuppressWarnings("unchecked")
    public List<User> listUser(TelephoneResourceSearch search) {
        String s = "SELECT telephoneResource.user " + search.buildSentenceTemplate();
        Map<String, Object> parameters = search.buildParameters();
        return genericDaoSupport.searchForList(s, parameters);
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.TelephoneResourceService#listSchedule(java.util.List, java.lang.Boolean)
     */
    public Map<Long, CourseSchedule> listSchedule(List<User> users, Boolean experienced) {
        List<CourseSchedule> courseSchedules = new ArrayList<>();
        
        if(experienced == null) {
            List<User> experiencedUsers = telephoneResourceDao.listExperiencedUser(CourseType.INDIVIDUAL, ScheduleStatus.FINISH, users);
            
            if(!experiencedUsers.isEmpty()) {
                courseSchedules.addAll(telephoneResourceDao.listCourseSchedule(CourseType.INDIVIDUAL, ScheduleStatus.FINISH, experiencedUsers));
            }
            
            users.removeAll(experiencedUsers);
            
            if(!users.isEmpty()) {
                List<ScheduleStatus> scheduleStatus = new ArrayList<>();
                scheduleStatus.add(ScheduleStatus.READY);
                scheduleStatus.add(ScheduleStatus.EXPIRY);
                
                courseSchedules.addAll(telephoneResourceDao.listCourseSchedule(CourseType.INDIVIDUAL, scheduleStatus, users));
            }
        } else if(experienced) {
            courseSchedules = telephoneResourceDao.listCourseSchedule(CourseType.INDIVIDUAL, ScheduleStatus.FINISH, users);
        } else {
            List<ScheduleStatus> scheduleStatus = new ArrayList<>();
            scheduleStatus.add(ScheduleStatus.READY);
            scheduleStatus.add(ScheduleStatus.EXPIRY);
            
            courseSchedules = telephoneResourceDao.listCourseSchedule(CourseType.INDIVIDUAL, scheduleStatus, users);
        }
        
        Map<Long, CourseSchedule> result = new HashMap<>();
        
        if(!courseSchedules.isEmpty()) {
            Student student = courseSchedules.get(0).getStudent();
            result.put(student.getUser().getId(), courseSchedules.get(0));
            
            for(CourseSchedule courseSchedule : courseSchedules) {
                if(courseSchedule.getStudent() != student) {
                    student = courseSchedule.getStudent();
                    result.put(student.getUser().getId(), courseSchedule);
                }
            }
        }

        return result;
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.TelephoneResourceService#listSchedule(java.util.List)
     */
    public Map<Long, CourseSchedule> listSchedule(List<User> users) {
    	List<ScheduleStatus> scheduleStatus = new ArrayList<>();
        scheduleStatus.add(ScheduleStatus.READY);
        scheduleStatus.add(ScheduleStatus.FINISH);
        scheduleStatus.add(ScheduleStatus.EXPIRY);
    	
    	List<CourseSchedule> courseSchedules = telephoneResourceDao.listCourseSchedule(CourseType.INDIVIDUAL, scheduleStatus, users);
    	
    	Map<Long, CourseSchedule> result = new HashMap<>();
        
        if(!courseSchedules.isEmpty()) {
            Student student = courseSchedules.get(0).getStudent();
            result.put(student.getUser().getId(), courseSchedules.get(0));
            
            for(CourseSchedule courseSchedule : courseSchedules) {
                if(courseSchedule.getStudent() != student) {
                    student = courseSchedule.getStudent();
                    result.put(student.getUser().getId(), courseSchedule);
                }
            }
        }

        return result;
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.TelephoneResourceService#listRoundCount(java.util.List)
     */
    public Map<Long, Long> listRoundCount(List<User> users) {
        List<Map<String, Object>> roundCounts = telephoneResourceDao.listRoundCount(users);
        
        Map<Long, Long> result = new HashMap<>();
        
        if(!roundCounts.isEmpty()) {
            for(Map<String, Object> roundCount : roundCounts) {
                if(roundCount.get("id") != null) {
                    result.put((long)roundCount.get("id"), (long)roundCount.get("total"));
                }
            }
        }
        
        return result;
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.TelephoneResourceService#listRoundPriceSum(java.util.List)
     */
    public Map<Long, Long> listRoundPriceSum(List<User> users) {
        List<Map<String, Object>> roundPriceSums = telephoneResourceDao.listRoundPriceSum(users);

        Map<Long, Long> result = new HashMap<>();
        
        if(!roundPriceSums.isEmpty()) {
            for(Map<String, Object> roundPriceSum : roundPriceSums) {
                if(roundPriceSum.get("id") != null) {
                    result.put((long)roundPriceSum.get("id"), (long)roundPriceSum.get("price"));
                }
            }
        }
        
        return result;
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.TelephoneResourceService#listTelephoneRecordCount(java.util.List)
     */
    public Map<Long, Long> listTelephoneRecordCount(List<TelephoneResource> telephoneResources) {
        List<Map<String, Object>> mapList = telephoneResourceDao.listTelephoneRecordCount(telephoneResources);
        
        Map<Long, Long> result = new HashMap<>();
        
        if(!mapList.isEmpty()) {
            for(Map<String, Object> map : mapList) {
                result.put((long)map.get("id"), (long)map.get("total"));
            }
        }
        
        return result;
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.TelephoneResourceService#listTelephoneRecordCount(java.util.Date, java.util.Date, java.lang.Boolean)
     */
    public Map<Long, Long> listTelephoneRecordCount(Date begin, Date end, Boolean experienced) {
    	List<Map<String, Object>> mapList = new ArrayList<>();
    	
    	if(experienced == null) {
    		mapList = telephoneResourceDao.listTelephoneRecordCount(begin, end);
    	} else {
    		mapList = telephoneResourceDao.listTelephoneRecordCount(begin, end, experienced);
    	}
    	
    	Map<Long, Long> result = new HashMap<>();
        
        if(!mapList.isEmpty()) {
            for(Map<String, Object> map : mapList) {
                result.put((long)map.get("id"), (long)map.get("total"));
            }
        }
        
        return result;
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.TelephoneResourceService#listTelephoneRecordCount(co.fitstart.admin.entity.search.TelephoneRecordSearch)
     */
    @SuppressWarnings("unchecked")
    public Map<Long, Long> listTelephoneRecordCount(TelephoneRecordSearch search) {
        String s = search.buildSentenceTemplate();
        Map<String, Object> parameters = search.buildParameters();
        
        List<Map<String, Object>> mapList = genericDaoSupport.searchForList(s, parameters);
        
        Map<Long, Long> result = new HashMap<>();
        
        if(!mapList.isEmpty()) {
            for(Map<String, Object> map : mapList) {
                if(map.get("id") != null) {
                    result.put((long)map.get("id"), (long)map.get("total"));
                }
            }
        }
        
        return result;
    }
}
